package poker;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import poker.preflopsim.PlayerStats;
import poker.preflopsim.PreFlopSimulator;

public class HandStrength 
{
	private static double[][] preflopHandStrength; 
	private static int startIndex[] = {0, 25, 48, 69, 88, 105, 120, 133, 144, 153, 160, 165, 168};
	
	static 
	{
		preflopHandStrength = loadPreflopFile("test.result");
	}
	
	private static double[][] loadPreflopFile(String filename)
	{
		double[][] fileStatistics = new double[169][9];
		BufferedReader reader = null;
		
		try
		{
			File file = new File(filename);
			reader = new BufferedReader(new FileReader(file));
			String line;
			int index = 0;
			while ((line=reader.readLine()) != null)
			{
				String[] numbers = line.split(" ");
				for(int i = 1; i < numbers.length; i++)
				{
					fileStatistics[index][i-1] = Double.valueOf(numbers[i]);
				}
				index++;
			}
			reader.close();
		} 
		catch(IOException e)
		{
			System.err.println("Failed to load preflop file");
			return null;
		}
		return fileStatistics;
	}
	
	public static double calculateHandStrength(Card[] hand, Card[] communityCards, int playersLeft)
	{
		Card[] deck = Deck.getCardsWithout(combine(hand, communityCards));
		Card[][] pairs = generatePairs(deck);

		PlayerStats stats = new PlayerStats();
		
		//Compare all pairs combined with S to see if it yields a better 5-card hand than H+S.
		for(int i = 0; i < pairs.length; i++)
		{
			int rating = HandPowerRating.compare(combine(hand, communityCards), combine(pairs[i], communityCards));
			if(rating == 1)
				stats.incWins();
			if(rating == 0)
				stats.incDraws();
			if(rating == -1)
				stats.incLosses();
		}
		return stats.handStrength(playersLeft -1);
	}
	
	public static double getHandStrengthPreFlop(Card[] hand, int playersLeft)
	{
		return preflopHandStrength[getIndex(hand)][playersLeft-2];
	}
	
	private static boolean sameSuit(Card card1, Card card2)
	{		
		return card1.getSuit() == card2.getSuit();
	}

	private static int getIndex(Card[] card)
	{
		Card[] sortedCards = ListUtils.sortForPrefix(card);
		boolean suit = sameSuit(sortedCards[0], sortedCards[1]);
		int index = startIndex[sortedCards[0].getValue() - 2];
		index += (sortedCards[1].getValue() - sortedCards[0].getValue())*2;
		if(suit) { index--;	}

		return index;		
	}
	
	private static Card[][] generatePairs(Card[] deck) 
	{
		//Hard-coded for speed optimization
		int size = 0;
		if(deck.length == 47)
			size = 1081;
		else if (deck.length == 46)
			size = 1035;
		else if (deck.length == 45)
			size = 990;
		
		
		Card[][] pairs = new Card[size][2];
		
		int index = 0;
		//Generate all possible pairs from the deck and return it;
		for (int i = 0; i < deck.length; i++) 
		{
			for (int j = i+1; j < deck.length; j++) 
			{
				Card otherHand[] = {deck[i], deck[j]};
				pairs[index] = otherHand;
				index++;
			}
		}

		return pairs;
	}

	public static Card[] combine(Card[] hand1, Card[] hand2)
	{
		Card[] newHand = new Card[hand1.length + hand2.length];
		for (int i = 0; i < hand1.length; i++) {
			newHand[i] = hand1[i];
		}
		for(int i = hand1.length; i < hand2.length + hand1.length; i++)
		{
			newHand[i] = hand2[i - hand1.length];
		}
		return newHand;
	}
}
